﻿namespace System.NETool;

/// <summary>
/// 提供用于计算 CRC16 Modbus 校验码的静态方法。
/// </summary>
public static class CRC16Modbus
{
    /// <summary>
    /// 计算指定数据的 CRC16 校验码。
    /// </summary>
    /// <param name="data">要计算校验码的数据。</param>
    /// <returns>计算得到的 CRC16 校验码。</returns>
    public static ushort ComputeHash(ReadOnlySpan<byte> data)
    {
        ushort crc = 0xFFFF;
        foreach (var t in data)
        {
            crc ^= t;
            for (int j = 0; j < 8; j++)
            {
                if ((crc & 0x0001) != 0)
                {
                    crc >>= 1;
                    crc ^= 0xA001;
                }
                else
                {
                    crc >>= 1;
                }
            }
        }

        return crc;
    }

    /// <summary>
    /// 计算指定数据的 CRC16 校验码，并将校验码附加到数据末尾。
    /// </summary>
    /// <param name="buffer">要计算校验码的数据。</param>
    /// <returns>附加了 CRC16 校验码的新数据数组。</returns>
    public static byte[] ComputeData(ReadOnlySpan<byte> buffer)
    {
        byte[] result = new byte[buffer.Length + 2];
        buffer.CopyTo(result);
        ushort crc = ComputeHash(buffer);
        result[^2] = (byte)(crc & 0xFF);
        result[^1] = (byte)(crc >> 8);
        return result;
    }
}

